package com.gzdcdata.xxorder.service.imp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gzdcdata.core.common.IDUtil;
import com.gzdcdata.core.common.PublicInterfaceWX;
import com.gzdcdata.wxpay.service.WXPayCommenService;
import com.gzdcdata.wxpay.service.WXPayService;
import com.gzdcdata.xxorder.dao.XxOrderDao;
import com.gzdcdata.xxorder.entity.XxOrder;
import com.gzdcdata.xxorder.entity.XxOrderDetail;
import com.gzdcdata.xxorder.service.XxOrderService;
import com.gzdcdata.xxorderitem.dao.XxOrderItemDao;
import com.gzdcdata.xxorderitem.entity.XxOrderItem;
import com.gzdcdata.xxorderitem.service.XxOrderItemService;
import com.gzdcdata.xxpayment.entity.XxPayment;
import com.gzdcdata.xxpayment.service.XxPaymentService;
import com.gzdcdata.xxproduct.dao.XxProductDao;
import com.gzdcdata.xxproduct.entity.XxProduct;
import com.gzdcdata.xxproduct.service.XxProductService;
import com.gzdcdata.xxreceiver.dao.XxReceiverDao;
import com.gzdcdata.xxreceiver.entity.XxReceiver;
import com.gzdcdata.xxshippingmethod.entity.XxShippingMethod;
import com.gzdcdata.xxshippingmethod.service.XxShippingMethodService;
import com.wxpay.gzdcdata.pay.WXPayConstants.SignType;
import com.wxpay.gzdcdata.pay.WXPayUtil;
import com.wxpay.gzdcdata.pay.impl.WXPayConfigImpl;
/**
 * 订单服务类
 * @author dsj
 *
 *
 */
@Service("xxOrderService")
public class XxOrderServiceImp implements XxOrderService {

	@Resource(name="xxOrderDao")
	private XxOrderDao xxOrderDao;
	@Resource(name="xxProductDao")
	private XxProductDao xxProductDao;
	@Resource(name="xxShippingMethodService")
	private XxShippingMethodService xxShippingMethodService;
	@Resource(name="xxReceiverDao")
	private XxReceiverDao xxReceiverDao;
	@Resource(name="xxPaymentService")
	private XxPaymentService xxPaymentService;
	@Resource(name="xxOrderItemService")
	private XxOrderItemService xxOrderItemService;
	@Resource(name="xxOrderItemDao")
	private XxOrderItemDao xxOrderItemDao;
	@Resource(name="xxProductService")
	private XxProductService xxProductService;

	@Resource(name="wXPayService")
	private WXPayService wXPayService;

	@Resource(name="wXPayCommenService")
	private WXPayCommenService wXPayCommenService;

	/**
     * 日志对象
     */
    protected Logger logger = LoggerFactory.getLogger(getClass());
    @Override
	public String  insertOrder(Long userId,Long addrId, String memo, List<XxProduct> list,String ipAddress) throws Exception{
		//还可以判断用户是否存在等 避免没用的数据
		if(userId==null||list==null||list.size()<1||addrId==null){
			throw new Exception("提交数据不合法");
		}
		Integer quantity=0;
		//存储查询到的详细商品信息
		List<XxProduct> xxProducts=new ArrayList<XxProduct>();
		for(XxProduct li:list){
			quantity=li.getQuantity();
			li=xxProductDao.getOrderXxProductByid(li.getId());
			li.setQuantity(quantity);
			xxProducts.add(li);
		}
		//存储不免邮的商品
		List<XxProduct> xxProductsNotFree=new ArrayList<XxProduct>();
		//计算商品价格
		Double shopTotalMoney=0.00;
		long points=0;
		for(XxProduct xxProduct:xxProducts){
			points+=xxProduct.getPoint();
			//把产品数量和价格转成BigInteger类型进行计算之后与之前的shopTotalMoney相加并赋值给shopTotalMoney
			shopTotalMoney=shopTotalMoney+xxProduct.getQuantity()*Double.valueOf(xxProduct.getPrice());
			if(!xxProduct.getIs_free_shipping()){//不免邮
				xxProductsNotFree.add(xxProduct);
			}
		}
		//地址信息
		XxShippingMethod xxShippingMethod = xxShippingMethodService.getDefaultInfo();
		//算邮费
		Double freight = calcuShippingMoney(xxProductsNotFree,xxShippingMethod);

		XxReceiver xxReceiver=xxReceiverDao.getById(addrId);
		//实例化订单对象
		XxOrder xxOrder =initOrderObject(xxReceiver,freight);
		String sn=String.valueOf(IDUtil.orderId());
		xxOrder.setSn(sn);
		xxOrder.setMemo(memo);
		xxOrder.setPoint(points);
		xxOrder.setShipping_method_name(xxShippingMethod.getRealname());
		xxOrder.setMember(userId);
		//保存订单对象并返回订单编号和主键
		logger.info("订单信息"+xxOrder);
		xxOrderDao.save(xxOrder);
		logger.info("订单插入成功并返回主键"+xxOrder.getId());
		logger.info("商品价格"+shopTotalMoney);
		//初始化收款单信息并存储
		XxPayment xxPayment=new XxPayment();
		xxPayment.setAmount(shopTotalMoney+freight);
		xxPayment.setFee(0d);
		xxPayment.setMethod(0);
		xxPayment.setSn(String.valueOf(IDUtil.orderId()));
		xxPayment.setStatus(0);
		xxPayment.setType(0);
		xxPayment.setMember(userId);
		xxPayment.setOrders(xxOrder.getId());
		logger.info("初始化收款单信息"+xxPayment);
		xxPaymentService.insertInit(xxPayment);
		logger.info("收款单编号"+xxPayment.getId());

		//初始化并存储子订单信息
		logger.info("初始化并存储子订单信息,所属订单"+xxOrder.getId());
		List<XxOrderItem> xxOrderItems=initXxOrderItem(xxProducts,xxOrder.getId()) ;
		xxOrderItemService.insertBatch(xxOrderItems);
		return sn;
	}

	@Override
	public List<XxOrderDetail> listByStatusAndUser(Integer order_status, Long userId, Integer page, Integer rows) throws Exception{
		PageHelper.startPage(page, rows);
		List<XxOrderDetail> list=xxOrderDao.listByStatusAndUser(order_status,userId);
		PageInfo<XxOrderDetail> pageInfo=new PageInfo<XxOrderDetail>(list);
		return pageInfo.getList();
	}
	@Override
	public Integer countByStatusMember(String memberId, String order_status) {
		return xxOrderDao.countByStatusMember(memberId,order_status);
	}
	@Override
	public void cancelOrder(String memberId, String sn) throws Exception{
		//更新订单状态
		xxOrderDao.updateOrderBySn(memberId,sn,3);
		//TODO 可能还要更新付款单的状态
	}

	/**
	 * 初始化子订单信息
	 * @param xxProducts :商品详情
	 * @return
	 */
	private List<XxOrderItem> initXxOrderItem(List<XxProduct> xxProducts,Long orderId) {
		List<XxOrderItem> list= new ArrayList<>();
		XxOrderItem xxOrderItem=null;
		for(XxProduct xxProduct:xxProducts){
			xxOrderItem=new XxOrderItem();
			xxOrderItem.setFull_name(xxProduct.getFull_name());
			xxOrderItem.setIs_gift(xxProduct.getIs_gift());
			xxOrderItem.setName(xxProduct.getName());
			xxOrderItem.setPrice(xxProduct.getPrice());
			xxOrderItem.setQuantity(xxProduct.getQuantity());
			xxOrderItem.setReturn_quantity(0);
			xxOrderItem.setShipped_quantity(0);
			xxOrderItem.setSn(String.valueOf(IDUtil.orderId()));
			xxOrderItem.setThumbnail(xxProduct.getThumbnail());
			xxOrderItem.setWeight(xxProduct.getWeight());
			xxOrderItem.setOrders(orderId);
			xxOrderItem.setProduct(xxProduct.getId());
			logger.info("子订单信息"+xxOrderItem);
			list.add(xxOrderItem);
		}
		return list;
	}
	/**
	 * 初始化订单信息
	 * @param xxReceiver
	 * @param freight
	 * @return
	 */
	private XxOrder initOrderObject(XxReceiver xxReceiver,Double freight){
		XxOrder xxOrder = new XxOrder();
		xxOrder.setAddress(xxReceiver.getAddress());
		xxOrder.setAmount_paid(0l);
		xxOrder.setArea_name(xxReceiver.getArea_name());
		xxOrder.setConsignee(xxReceiver.getConsignee());
		xxOrder.setCoupon_discount(0l);
		xxOrder.setFee(0l);
		xxOrder.setFreight(Long.valueOf(freight.intValue()));
		xxOrder.setIs_allocated_stock(false);
		xxOrder.setIs_invoice(false);
		xxOrder.setOffset_amount(0l);
		xxOrder.setOrder_status(0);
		xxOrder.setPayment_method_name("网上支付");
		xxOrder.setPayment_status(0);
		xxOrder.setPhone(xxReceiver.getPhone());
		xxOrder.setPromotion_discount(0l);
		xxOrder.setShipping_status(0);

		xxOrder.setTax(0l);
		xxOrder.setZip_code("000000");
		xxOrder.setArea(xxReceiver.getArea());
		xxOrder.setPayment_method(1l);
		xxOrder.setShipping_method(1l);
		return xxOrder;
	}
	/**
	 * 邮费计算：TODO 暂时这么计算 根据实际在进行修改
	 * @param xxProducts
	 * @return
	 * @throws Exception
	 */
	private Double calcuShippingMoney(List<XxProduct> xxProducts,XxShippingMethod xxShippingMethod) throws Exception{
		//不管是否超重初始化一个未操作价格
		Double  shopTotalMoney=xxShippingMethod.getFirst_price().doubleValue();
		for(XxProduct xxProduct:xxProducts){
			if(xxProduct.getWeight()>xxShippingMethod.getFirst_weight()){//大于首重
				//大于首重价格 物体重量   减去   首重量  然后  除以续重之后取整数 所得结果为续重价格
				//初始化产品重量b1
				Double b1=xxProduct.getWeight().doubleValue();
				//首重
				Double firstWight = xxShippingMethod.getFirst_weight().doubleValue();
				//续重量
				Double b2=xxShippingMethod.getContinue_weight().doubleValue();
				//续重单价
				Double b3=xxShippingMethod.getContinue_price().doubleValue();
				//续重价格
				Double continueMoney = (b1-firstWight)/b2*b3;
				shopTotalMoney+=continueMoney;
			}
		}
		return shopTotalMoney;
	}
	@Override
	public XxOrderDetail getOrderDetatil(String sn, String memberId) {
		XxOrderDetail xxOrderDetail=xxOrderDao.selectOrderBySnAndMember(sn,memberId);
		if(xxOrderDetail==null||xxOrderDetail.getId()==null){
			return null;
		}
		List<XxOrderItem> xxOrderItems=xxOrderItemDao.selListByOrderId(xxOrderDetail.getId());
		xxOrderDetail.setXxOrderItems(xxOrderItems);
		XxPayment xxPayment = xxPaymentService.getByOrderId(xxOrderDetail.getId());
		xxOrderDetail.setXxPayment(xxPayment);
		return xxOrderDetail;
	}
	@Override
	public Map<String, String> paySuccess( Map<String ,String> map,int order_status) throws Exception{
		Map<String, String> resultMap = new HashMap<String,String>();
		logger.info("微信回调给给的数据"+map);
		if(map.get("return_code").equals("SUCCESS")&&map.get("result_code").equals("SUCCESS")){//数据正常
			//商户系统对于支付结果通知的内容(一定要)做签名验证,
			WXPayConfigImpl wXPayCongifg=WXPayConfigImpl.getInstance();
			boolean signStatus= WXPayUtil.isSignatureValid(map, wXPayCongifg.getKey(), SignType.HMACSHA256);

			if(!signStatus){//数据签名验证不正确,说明给的数据不对
				logger.info("数据非法!");
				resultMap.put("return_code","FAIL");
				resultMap.put("return_msg","签名验证未通过,数据非法!");
				return resultMap;
			}
			//付款单编号sn
			String paymentSn=map.get("out_trade_no");
			//TODO 数据校验:暂时没有做优惠券等等 只要校验现金支付金额cash_fee
			String cash_fee= map.get("cash_fee");//现金支付金额
			XxPayment xxPayment=xxPaymentService.queryBySn(paymentSn);
			String total_fee=String.valueOf(xxPayment.getAmount()*100);//本地订单金额
	        total_fee=total_fee.substring(0, total_fee.indexOf("."));
	        logger.info("金额检验"+cash_fee);
	        logger.info("金额检验本地订单金额"+total_fee);
	        if(cash_fee.equals(total_fee)){//金额检验正确
	        	logger.info("金额检验正确");
	        	//订单状态更新
	        	xxOrderDao.updateStatusByPaymentId(String.valueOf(xxPayment.getId()),order_status);//订单已确认  已支付
	        	//本地付款单更新TODO更多字段

	        	/*{transaction_id=4200000125201805149151058625,
	        			nonce_str=a092fb267c2f439ab24a9ca83091d40f,
	        			bank_type=CFT,
	        			openid=oo1HL1MO2EhFqhOKvs2eOopsUvXY,
	        			sign=0E7FB92FA9AAB0A5E1DD911687C2598972099C034428680DD8ACF35D9135DF43,
	        			fee_type=CNY,
	        			mch_id=1481627572,
	        			cash_fee=1,
	        			device_info=WEB,
	        			out_trade_no=201805141059398383,
	        			appid=wx3a59d3c5f923218e,
	        			total_fee=1,
	        			trade_type=JSAPI,
	        			result_code=SUCCESS,
	        			time_end=20180514110052,
	        			is_subscribe=Y,
	        			return_code=SUCCESS}*/
	        	//bank_type//付款银行
	        	//交易类型
	        	xxPaymentService.updateStatusByPaymentId(map.get("trade_type"),String.valueOf(xxPayment.getId()), order_status); //收款单已支付

	        	//通知卖家发货
	        	// 可能存在一个订单购买多个商家商品的情况
	        	XxOrder xxorder = xxOrderDao.selectOrderById(Long.valueOf(xxPayment.getOrders()));
	        	logger.info("订单状态已修改，支付单状态已修改，发送模板通知商家发货....."+JSONObject.toJSONString(xxorder));
	        	List<Map<String, Object>>  openids = xxProductService.getopenIdByOrderId(xxorder.getId());
	        	if(openids!=null&&openids.size()>0){
	                for (Map<String, Object> openid : openids) {
	                    List<String> list = new ArrayList<String>();
	                	list.add((String)openid.get("openid"));
	                	list.add("您好，您的客户已付款，请尽快发货哦");
	                	list.add(xxorder.getConsignee());
	                	list.add(xxorder.getPhone());
	                	list.add(xxorder.getArea_name()+" "+xxorder.getAddress());
	                	list.add("请登录商城管理平台发货");
	                	String msg = PublicInterfaceWX.goodsDeliver(list);
	                	System.out.println("模板发送结果==="+msg);
					}
	        	}else{
	        		logger.info("某个商品分类未分配商家openid,未能发送到发货通知");
	        	}
	        	resultMap.put("return_code","SUCCESS");
				resultMap.put("return_msg","OK");
	        }else{//金额校验错误
	        	logger.info("金额检验错误");
	        	resultMap.put("return_code","FAIL");
				resultMap.put("return_msg","支付失败!");
	        }
		}else{
			logger.info("微信返回支付失败");
			resultMap.put("return_code","FAIL");
			resultMap.put("return_msg","支付失败");
		}
		return resultMap;
	}



	@Override
	public void acceptOk(String userId, String sn) {
		//更新订单状态
		xxOrderDao.updateOrderBySn(userId,sn,2);
	}
	@Override
	public List<XxOrderItem> getProductByOrderSn(String sn) {
		return xxOrderItemDao.getByOrderSn(sn);
	}
	@Override// TODO  生成微信商户订单
	public Map<String, String> payOrder(String paymentSn, String ipAddress,String payOpenid) throws Exception {
		XxPayment xxPayment = xxPaymentService.queryBySn(paymentSn);
		Map<String, String> result = createWXPayUnifiedOrder(xxPayment,ipAddress,payOpenid);
 		return result;
	}
	    /**
	     * 生成微信商户订单
	     * @throws Exception
	     */
		private Map<String, String> createWXPayUnifiedOrder(XxPayment xxPayment,String ipAddress,String payOpenid) throws Exception {
			HashMap<String, String> data = new HashMap<String, String>();
	        data.put("body", "ygt-spfk");
	        data.put("out_trade_no", xxPayment.getSn());
	        data.put("device_info", "WEB");
	        data.put("fee_type", "CNY");
	        String total_fee=String.valueOf(xxPayment.getAmount()*100);
	        total_fee=total_fee.substring(0, total_fee.indexOf("."));
	        data.put("total_fee",total_fee);
	        data.put("spbill_create_ip", ipAddress);
	        //这个地址是微信付款成功后异步发送到用户服务器上更新订单状态的回调地址
	        data.put("notify_url", "http://pos.gzdcdata.com/WxShop/xxorder/paySuccess");
	        data.put("trade_type", "JSAPI");
	        data.put("sign_type", "MD5");

	       // String openid=wXPayCommenService.getWXInfo(code).getString("openid");

	        data.put("openid", payOpenid);
	        logger.info("支付公众号payOpenid=========================>"+payOpenid);
	        Map<String, String> result = wXPayService.doUnifiedOrder(data);

	        logger.info("=========================>"+result);
			if(!result.get("result_code").equals("SUCCESS")){
				throw new Exception(result.get("return_msg"));
			}

			// 得到下单后返回的result并取出其中部分数据签名返回前台以便前台调用jsAPI支付申请
			Map<String, String> signMap=new HashMap<String, String>();
			signMap.put("appId", result.get("appid"));
			signMap.put("timeStamp",  Integer.valueOf(System.currentTimeMillis()/1000+"")+"");
			signMap.put("nonceStr",result.get("nonce_str"));
			signMap.put("package", "prepay_id="+result.get("prepay_id"));
			signMap.put("signType", "HMAC-SHA256");

			WXPayConfigImpl wXPayConfig=WXPayConfigImpl.getInstance();
			signMap.put("sign", WXPayUtil.generateSignature(signMap, wXPayConfig.getKey(),SignType.HMACSHA256));

			logger.info("=========================>"+signMap);

			return signMap;
		}

		//private

		public static void main(String[] args) throws Exception {
			/*{transaction_id=4200000124201805117260881926,
					nonce_str=b2b12f67d5f743c8b2d06a09a2d257f5,
					bank_type=CFT,
					openid=oo1HL1MO2EhFqhOKvs2eOopsUvXY,
					//sign=4889D089BAB646C49BBF57F308D104398DBB2A4A141D269F7C6C1C14805DE607,
					fee_type=CNY,
					mch_id=1481627572,
					cash_fee=1,
					device_info=WEB,
					 out_trade_no=201805111033550221,
					 appid=wx3a59d3c5f923218e,
					 total_fee=1,
					 trade_type=JSAPI,
					 result_code=SUCCESS,
					 time_end=20180511103514,
					 is_subscribe=Y,
					// return_code=SUCCESS}
*/
			HashMap<String, String> data = new HashMap<String, String>();
	        data.put("transaction_id", "4200000124201805117260881926");
	        data.put("nonce_str","b2b12f67d5f743c8b2d06a09a2d257f5");
	        data.put("bank_type", "CFT");
	        data.put("openid", "oo1HL1MO2EhFqhOKvs2eOopsUvXY");
	        data.put("fee_type","CNY");
	        data.put("sign","4889D089BAB646C49BBF57F308D104398DBB2A4A141D269F7C6C1C14805DE607");

	        data.put("mch_id", "1481627572");
	        data.put("cash_fee", "1");
	        data.put("device_info", "WEB");
	        data.put("out_trade_no", "201805111033550221");
	        data.put("appid", "wx3a59d3c5f923218e");

	        data.put("total_fee", "1");
	        data.put("trade_type", "JSAPI");
	        data.put("time_end", "20180511103514");
	        data.put("is_subscribe", "Y");
	        data.put("result_code","SUCCESS");
	        data.put("return_code","SUCCESS");

	        /*String sign = data.get("sign");
	        data.remove("sign");*/
			WXPayConfigImpl wXPayCongifg=WXPayConfigImpl.getInstance();
	         boolean result = WXPayUtil.isSignatureValid(data, wXPayCongifg.getKey(), SignType.HMACSHA256);
	        	System.out.println(result);
		}
}
